#define DOHOME_LOG_LVL          DOHOME_LOG_LVL_DEBUG
#define DOHOME_LOG_TAG          "factory"


#include "doit_factory_test.h"

#include <dohome_log.h>
#include <dohome_api.h>
#include <dohome_hal_wifi.h>
#include <dohome_hal_gpio.h>

#include "doit_product.h"
#include "doit_default_cfg.h"
#include "doit_switch_lib.h"
#include "flexible_button.h"
#include "doit_product_cfg.h"

#if (defined(CONFIG_POWER_MEASURE_ENABLE_CORRECT) && CONFIG_POWER_MEASURE_ENABLE_CORRECT == 1)
#include "dohome_hal_pwr_measure.h"
#endif


#if ((DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFI) || (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFIBLE))   
#ifndef FACTORY_TEST_SSID
// #define FACTORY_TEST_SSID            "636F7A796C6966655F74657374"
#define FACTORY_TEST_SSID               "CozyLife_CC"
#endif


#define FACTORY_TEST_CONTROL_ENABLE     1

#if (defined(FACTORY_TEST_CONTROL_ENABLE) && FACTORY_TEST_CONTROL_ENABLE == 1)
#define FACTORY_TEST_CONTROL_SSID       "CozyLife_Upgrade"
#define FACTORY_TEST_CONTROL_PWD        "12345678"
#endif

#ifndef DOHOME_FACTORY_SWITCH_REVERSE_CNT
#define DOHOME_FACTORY_SWITCH_REVERSE_CNT                   1    
#endif

#define DOHOME_FACTORY_TEST_SCAN_RANDOM_MAX                 20
#define DOHOME_FACTORY_TEST_MIN_RSSI                        (-80)
#define DOHOME_FACTORY_TEST_LOOP_INTERVAL                   DOIT_LOOP_PERIOD // ms


#define DOHOME_FACTORY_TEST_SWITCH_REVERSE_INTERVAL         (500/DOIT_LOOP_PERIOD*DOIT_LOOP_PERIOD)
#define DOHOME_FACTORY_TEST_LED_FLASH_INTERVAL              (150/DOIT_LOOP_PERIOD*DOIT_LOOP_PERIOD)


#define DOHOME_FACTORY_TEST_STA_IDEL              0
#define DOHOME_FACTORY_TEST_STA_SCAN_BEGIN        1
#define DOHOME_FACTORY_TEST_STA_SCAN_DELAY        2
#define DOHOME_FACTORY_TEST_SCANWFI               3
#define DOHOME_FACTORY_TEST_STA_WAIT              4
#define DOHOME_FACTORY_TEST_STA_END               5
#define DOHOME_FACTORY_TEST_WAIT_FOR_SCANWFI      6
#define DOHOME_FACTORY_TEST_CHECK                 7
#define DOHOME_FACTORY_TEST_SSID_FOUND            8
#define DOHOME_FACTORY_TEST_SSID_NOT_FOUND        9

#define DOHOME_FACTORY_TEST_STA_LOW_FUN           10
#define DOHOME_FACTORY_TEST_STA_TEST_FUN          11

#define DOHOME_FACTORY_TEST_THIRD_PARTY           13

#if (defined(FACTORY_TEST_CONTROL_ENABLE) && FACTORY_TEST_CONTROL_ENABLE == 1)
#define DOHOME_FACTORY_TEST_CONTROL               12
#endif

DOHOME_STATIC DOHOME_UINT8_T _scan_num = 0;
DOHOME_STATIC DOHOME_UINT8_T _scan_count = 0;
DOHOME_STATIC DOHOME_UINT8_T _factory_test_sta = DOHOME_FACTORY_TEST_STA_IDEL;

DOHOME_STATIC doit_test_scan_cb_t _test_scan_cb = NULL;
DOHOME_STATIC DOHOME_UINT16_T dt_test_rssi_low = 0;
DOHOME_STATIC DOHOME_INT16_T dt_test_rssi_average = 0;

DOHOME_STATIC dt_switch_io_cfg_t switch_cfg[CONFIG_SWITCH_NUM] = {
SWITCH_IO_1
SWITCH_IO_2
SWITCH_IO_3
SWITCH_IO_4
SWITCH_IO_5
SWITCH_IO_6
SWITCH_IO_7
SWITCH_IO_8
};


DOHOME_UINT8_T _third_party_enable = 0;
DOHOME_CHAR_T _third_party_ssid[33] = {0};
doit_test_scan_cb_t _third_party_scan_cb = NULL;

DOHOME_STATIC void dt_test_rssi_low_func(void);

#if (defined(FACTORY_TEST_CONTROL_ENABLE) && FACTORY_TEST_CONTROL_ENABLE == 1)
void dt_test_control_start(void){
    dohome_hal_wifi_set_mode(DOHOME_WIFI_MODE_STATION);
    dohome_hal_wifi_station_connect(FACTORY_TEST_CONTROL_SSID, FACTORY_TEST_CONTROL_PWD);
}
#endif

void doit_factory_register_third_party_test(DOHOME_CHAR_T *ssid, doit_test_scan_cb_t test_scan_cb){

    if(dohome_safe_strlen(ssid, 33-1)){
        _third_party_enable = 1;
        strcpy(_third_party_ssid, ssid);
        _third_party_scan_cb = test_scan_cb;
    }
}


DOHOME_STATIC void wifi_csan_cb(dohome_ap_info_t *ap_list, DOHOME_UINT8_T num){

    if(_factory_test_sta == DOHOME_FACTORY_TEST_STA_IDEL){
        return;
    }

    DOHOME_UINT8_T i = 0;
    DOHOME_INT16_T value = 0;

    for (i = 0; i < num; i++)
    {
        dohome_printf("AP%02d  rssi:%d  channel:%d  ssid:%.*s\n", i+1, ap_list[i].rssi, ap_list[i].channel, ap_list[i].ssid_len, ap_list[i].ssid);

#if (defined(FACTORY_TEST_CONTROL_ENABLE) && FACTORY_TEST_CONTROL_ENABLE == 1)
        if((strlen(FACTORY_TEST_CONTROL_SSID) == ap_list[i].ssid_len) &&
            (0 == memcmp(FACTORY_TEST_CONTROL_SSID, ap_list[i].ssid, ap_list[i].ssid_len)))
        {
            _factory_test_sta = DOHOME_FACTORY_TEST_CONTROL;
            return;
        }
#endif

        if(_third_party_enable == 1){
            if((strlen(_third_party_ssid) == ap_list[i].ssid_len) &&
                (0 == memcmp(_third_party_ssid, ap_list[i].ssid, ap_list[i].ssid_len)))
            {
                _factory_test_sta = DOHOME_FACTORY_TEST_THIRD_PARTY;
                return;
            }
        }

        if((strlen(FACTORY_TEST_SSID) == ap_list[i].ssid_len) &&
                (0 == memcmp(FACTORY_TEST_SSID, ap_list[i].ssid, ap_list[i].ssid_len)))
        {
            dt_test_rssi_average = (dt_test_rssi_average+ap_list[i].rssi)/2;
            if(ap_list[i].rssi < (DOHOME_FACTORY_TEST_MIN_RSSI+10)){
                dt_test_rssi_low = 1;
            }else{
                if(dt_test_rssi_low != 1){
                    _factory_test_sta = DOHOME_FACTORY_TEST_SSID_FOUND;
                    return;
                }
            }
        }
    }

    if(_scan_count >= _scan_num){

        if(dt_test_rssi_low){
            if(dt_test_rssi_average > DOHOME_FACTORY_TEST_MIN_RSSI){
                dt_test_rssi_low = 0;
            }else{
                DOHOME_LOG_E("test_ssid_rssi_low: %d", dt_test_rssi_average);
            }
            _factory_test_sta = DOHOME_FACTORY_TEST_SSID_FOUND;
            return;
        }
        _factory_test_sta = DOHOME_FACTORY_TEST_SSID_NOT_FOUND;
    }else{
        _factory_test_sta = DOHOME_FACTORY_TEST_STA_SCAN_BEGIN;
    }
}

DOHOME_STATIC DOHOME_UINT8_T _reverse_cnt[CONFIG_SWITCH_NUM] = {0};
DOHOME_STATIC DOHOME_UINT8_T _switch_status[CONFIG_SWITCH_NUM] = {0};

dohome_op_ret _switch_set_onoff(DOHOME_UINT8_T num, DOHOME_UINT8_T onoff){

    if(num > CONFIG_SWITCH_NUM-1){
        return OPRT_COM_ERROR;
    }

    if(switch_cfg[num].power_gpio.name != GPIO_NOT_USE){
        if(switch_cfg[num].power_gpio.active_level){
            dohome_hal_gpio_write(switch_cfg[num].power_gpio.name, onoff?1:0);
        }else{
            dohome_hal_gpio_write(switch_cfg[num].power_gpio.name, onoff?0:1);
        }
    }
    
    if(switch_cfg[num].state_gpio.name != GPIO_NOT_USE && switch_cfg[num].state_gpio.name != CONFIG_WIFI_STATE_PIN){
        if(switch_cfg[num].state_gpio.active_level){
            dohome_hal_gpio_write(switch_cfg[num].state_gpio.name, onoff?1:0);
        }else{
            dohome_hal_gpio_write(switch_cfg[num].state_gpio.name, onoff?0:1);
        }
    }
    _switch_status[num] = onoff;
    return OPRT_OK;
}


DOHOME_UINT8_T _switch_get_onoff(DOHOME_UINT8_T num){
    return _switch_status[num];
}

DOHOME_STATIC void _switch_reverse_loop(void){
    DOHOME_UINT8_T i = 0;
    for (i = 0; i < CONFIG_SWITCH_NUM; i++)
    {
        if(_reverse_cnt[i] != 0){
            _reverse_cnt[i]--;
            if(_switch_get_onoff(i)){
                _switch_set_onoff(i, 0);
            }else{
                _switch_set_onoff(i, 1);
            }
        }
    }
}

DOHOME_STATIC void _switch_reverse_loop2(void){
    DOHOME_UINT8_T i = 0;
    for (i = 0; i < CONFIG_SWITCH_NUM; i++)
    {
        if(_reverse_cnt[i] != 0){
            _reverse_cnt[i]--;
            if(_switch_get_onoff(i)){
                dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, !CONFIG_GPIO_STATE_ACTIVE_LEVEL);
                _switch_set_onoff(i, 0);
            }else{
                dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, CONFIG_GPIO_STATE_ACTIVE_LEVEL);
                _switch_set_onoff(i, 1);
            }
        }
    }
    
}


DOHOME_STATIC void _led_flash_loop(void){
    DOHOME_STATIC DOHOME_UINT8_T i = 0;
    
    if(CONFIG_WIFI_STATE_PIN != GPIO_NOT_USE){
        if(i++%2){
            dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, !CONFIG_GPIO_STATE_ACTIVE_LEVEL);
        }else{
            dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, CONFIG_GPIO_STATE_ACTIVE_LEVEL);
        }
    }
    
}

DOHOME_STATIC void _switch_reverse_cnt(DOHOME_UINT8_T num, DOHOME_UINT8_T cnt){
    _reverse_cnt[num] += cnt; 
}   


DOHOME_STATIC void _btn_evt_cb(void *arg)
{
    flex_button_t *btn = (flex_button_t *)arg;
    
    flex_button_t res_btn = {0};
    res_btn.event = btn->event;
    res_btn.click_cnt = btn->click_cnt;

    DOHOME_LOG_I("id: [%d]  event: [%d]  repeat: %d", btn->id, btn->event, btn->click_cnt);

    DOHOME_UINT8_T i = 0;
    switch (btn->event)
    {
    case FLEX_BTN_PRESS_CLICK:
        for (i = 0; i < CONFIG_SWITCH_NUM; i++){
            if(btn->id == switch_cfg[i].key_gpio.name){
                _switch_reverse_cnt(i, DOHOME_FACTORY_SWITCH_REVERSE_CNT);
                res_btn.id = i;
                break;
            }
        }
        break;
    case FLEX_BTN_PRESS_LONG_HOLD:

        break;
    default:
        break;
    }
}

DOHOME_STATIC DOHOME_UINT8_T _btn_read(void *arg)
{
    flex_button_t *btn = (flex_button_t *)arg;
    return dohome_hal_gpio_read(btn->id);
}


void factory_test_begin(){
    DOHOME_STATIC flex_button_t user_button[CONFIG_SWITCH_NUM];

    DOHOME_UINT8_T i = 0;
    
    flex_button_delete_all();

    for (i = 0; i < CONFIG_SWITCH_NUM; i++){

        user_button[i].id = switch_cfg[i].key_gpio.name;
        user_button[i].usr_button_read = _btn_read;
        user_button[i].cb = _btn_evt_cb;
        user_button[i].pressed_logic_level = 0;
        user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500);
        user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000);
        user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(3100);
        flex_button_register(&user_button[i]);

        if(switch_cfg[i].power_gpio.active_level){
            dohome_hal_gpio_write(switch_cfg[i].power_gpio.name, 0);
        }else{
            dohome_hal_gpio_write(switch_cfg[i].power_gpio.name, 1);
        }

        if(switch_cfg[i].state_gpio.name != GPIO_NOT_USE){
            if(switch_cfg[i].state_gpio.active_level){
                dohome_hal_gpio_write(switch_cfg[i].state_gpio.name, 0);
            }else{
                dohome_hal_gpio_write(switch_cfg[i].state_gpio.name, 1);
            }
        } 
    }

    if(CONFIG_WIFI_STATE_PIN != GPIO_NOT_USE){
        if(CONFIG_GPIO_STATE_ACTIVE_LEVEL){
            dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, 0);
        }else{
            dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, 1);
        }
    }
}

void doit_factory_test_init(DOHOME_UINT8_T scan_num, doit_test_scan_cb_t test_scan_cb){

    _scan_num = scan_num;
    _test_scan_cb = test_scan_cb;
    _scan_count = 0;
    _factory_test_sta = DOHOME_FACTORY_TEST_STA_SCAN_BEGIN; 
}

void doit_factory_test_loop(void){
    DOHOME_UINT8_T i = 0;

    DOHOME_STATIC DOHOME_UINT16_T delay_cnt = 0;
    DOHOME_STATIC DOHOME_UINT64_T loop_tick = 0;
    DOHOME_STATIC DOHOME_UINT16_T measure_tick = 0;

    DOHOME_SIZE_T len = 0;
    DOHOME_UINT32_T is_measure = 0;

    switch (_factory_test_sta)
    {
    case DOHOME_FACTORY_TEST_STA_IDEL:

        break;
    case DOHOME_FACTORY_TEST_STA_SCAN_BEGIN:

        DOHOME_LOG_D("DOHOME_FACTORY_TEST_STA_SCAN_BEGIN\n");
        delay_cnt = dohome_random(0, DOHOME_FACTORY_TEST_SCAN_RANDOM_MAX);
        _factory_test_sta = DOHOME_FACTORY_TEST_WAIT_FOR_SCANWFI;
        break;
    case DOHOME_FACTORY_TEST_WAIT_FOR_SCANWFI:
        if(delay_cnt == 0){
            _factory_test_sta = DOHOME_FACTORY_TEST_SCANWFI;
        }else{
            delay_cnt--;
        }
        break;
    case DOHOME_FACTORY_TEST_SCANWFI:
        _scan_count++;
        DOHOME_LOG_I("wifi_scan_start cnt: %d", _scan_count);
        dohome_hal_wifi_scan_start(wifi_csan_cb);
        _factory_test_sta = DOHOME_FACTORY_TEST_STA_WAIT;
        break;
    case DOHOME_FACTORY_TEST_SSID_FOUND:
        DOHOME_LOG_D("found factory ssid");
        if(_test_scan_cb){
            _test_scan_cb(1);
        }
        factory_test_begin();
        _factory_test_sta = DOHOME_FACTORY_TEST_CHECK;
        break;
    case DOHOME_FACTORY_TEST_SSID_NOT_FOUND:
        DOHOME_LOG_D("factory ssid not found");
        if(_test_scan_cb){
            _test_scan_cb(0);
        }
        _factory_test_sta = DOHOME_FACTORY_TEST_STA_IDEL;
        break;
    case DOHOME_FACTORY_TEST_CHECK:
        if(dt_test_rssi_low){
            _factory_test_sta = DOHOME_FACTORY_TEST_STA_LOW_FUN;
        }else{
            _factory_test_sta = DOHOME_FACTORY_TEST_STA_TEST_FUN;
        }
        // break;
    case DOHOME_FACTORY_TEST_STA_LOW_FUN:
        flex_button_scan(DOIT_LOOP_PERIOD);
        if(loop_tick%DOHOME_FACTORY_TEST_SWITCH_REVERSE_INTERVAL == 0){
            _switch_reverse_loop();
        }
        break;
    case DOHOME_FACTORY_TEST_STA_TEST_FUN:
        flex_button_scan(DOIT_LOOP_PERIOD);
#if (defined(CONFIG_POWER_MEASURE_ENABLE_CORRECT) && CONFIG_POWER_MEASURE_ENABLE_CORRECT == 1)
        if(measure_tick < (CONFIG_POWER_MEASURE_DEFAULT_CORRECT_TIME/DOIT_LOOP_PERIOD)){
            if(measure_tick==0){
#if (defined(CONFIG_POWER_MEASURE_REPEAT_CORRECT) && CONFIG_POWER_MEASURE_REPEAT_CORRECT == 0)
                dohome_kvs_get_env_blob("dt_pwrm", &is_measure, sizeof(is_measure), &len);
                if(is_measure == 1){
                    measure_tick = 0xFFFF;
                    break;
                }
#endif
                dohome_hal_pwr_measure_correct_init();
                _switch_set_onoff(0, 1);
            }
            measure_tick++;
            if(loop_tick%DOHOME_FACTORY_TEST_LED_FLASH_INTERVAL == 0){
                _led_flash_loop();
            }
        }else if (measure_tick == (CONFIG_POWER_MEASURE_DEFAULT_CORRECT_TIME/DOIT_LOOP_PERIOD)){
            DOHOME_UINT16_T power = dohome_hal_pwr_measure_get_active_power_W();
            DOHOME_UINT16_T power_diff = (power>CONFIG_POWER_MEASURE_DEFAULT_CORRECT_POWER_EXPECTED)?(power-CONFIG_POWER_MEASURE_DEFAULT_CORRECT_POWER_EXPECTED):(CONFIG_POWER_MEASURE_DEFAULT_CORRECT_POWER_EXPECTED-power);

            DOHOME_UINT16_T voltage = -1;
            DOHOME_UINT16_T voltage_diff = 0;
            if(CONFIG_POWER_MEASURE_DEFAULT_CORRECT_VOLTAGE_EXPECTED > 0){ 
                voltage = dohome_hal_pwr_measure_get_voltage_V();
                voltage_diff = (voltage>CONFIG_POWER_MEASURE_DEFAULT_CORRECT_VOLTAGE_EXPECTED)?(voltage-CONFIG_POWER_MEASURE_DEFAULT_CORRECT_VOLTAGE_EXPECTED):(CONFIG_POWER_MEASURE_DEFAULT_CORRECT_VOLTAGE_EXPECTED-voltage);
            }

            DOHOME_UINT16_T current = -1;
            DOHOME_UINT16_T current_diff = 0;
            if(CONFIG_POWER_MEASURE_DEFAULT_CORRECT_CURRENT_EXPECTED > 0){
                current = dohome_hal_pwr_measure_get_current_mA();
                current_diff = (current>CONFIG_POWER_MEASURE_DEFAULT_CORRECT_CURRENT_EXPECTED)?(current-CONFIG_POWER_MEASURE_DEFAULT_CORRECT_CURRENT_EXPECTED):(CONFIG_POWER_MEASURE_DEFAULT_CORRECT_CURRENT_EXPECTED-current);
            }
            
            printf("[PWR] V: %d  A: %d  P: %d\n", voltage, current, power); 

            printf("[PWR_diff] V: %d  A: %d  P: %d\n", voltage_diff, current_diff, power_diff);  

            if (voltage == 0 && current == 0 && power == 0)
            {
                DOHOME_LOG_L("pwr_measure_correct_error");
                dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, !CONFIG_GPIO_STATE_ACTIVE_LEVEL);
            }else if(voltage_diff > (CONFIG_POWER_MEASURE_DEFAULT_CORRECT_VOLTAGE_EXPECTED*CONFIG_POWER_MEASURE_DEFAULT_CORRECT_FAULT_TOLERANT/100)
                    || current_diff > (CONFIG_POWER_MEASURE_DEFAULT_CORRECT_CURRENT_EXPECTED*CONFIG_POWER_MEASURE_DEFAULT_CORRECT_FAULT_TOLERANT/100)
                    || power_diff > (CONFIG_POWER_MEASURE_DEFAULT_CORRECT_POWER_EXPECTED*CONFIG_POWER_MEASURE_DEFAULT_CORRECT_FAULT_TOLERANT/100)){
                DOHOME_LOG_L("pwr_measure_correct_low");
                dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, !CONFIG_GPIO_STATE_ACTIVE_LEVEL);
            }else{
                DOHOME_LOG_I("pwr_measure_correct");
                dohome_hal_pwr_measure_correct_for_expected(CONFIG_POWER_MEASURE_DEFAULT_CORRECT_VOLTAGE_EXPECTED, CONFIG_POWER_MEASURE_DEFAULT_CORRECT_CURRENT_EXPECTED, CONFIG_POWER_MEASURE_DEFAULT_CORRECT_POWER_EXPECTED);
                dohome_hal_gpio_write(CONFIG_WIFI_STATE_PIN, CONFIG_GPIO_STATE_ACTIVE_LEVEL);
#if (defined(CONFIG_POWER_MEASURE_REPEAT_CORRECT) && CONFIG_POWER_MEASURE_REPEAT_CORRECT == 0)
                is_measure = 1;
                dohome_kvs_set_env_blob("dt_pwrm", &is_measure, sizeof(is_measure));
#endif
            }
            _switch_set_onoff(0, 0);

            for (i = 0; i < CONFIG_SWITCH_NUM; i++){
                _switch_reverse_cnt(i, 0);
            } 
            measure_tick = 0xFFFF;
        }else if(measure_tick == 0xFFFF){
            if(loop_tick%DOHOME_FACTORY_TEST_SWITCH_REVERSE_INTERVAL == 0){
                _switch_reverse_loop2();
            }
        }
#else       
        if(loop_tick%DOHOME_FACTORY_TEST_LED_FLASH_INTERVAL == 0){
            _led_flash_loop();
        }
        if(loop_tick%DOHOME_FACTORY_TEST_SWITCH_REVERSE_INTERVAL == 0){
            _switch_reverse_loop();
        }
#endif
        break;
    case DOHOME_FACTORY_TEST_STA_WAIT:
            // wait for timeout
        break;
    case DOHOME_FACTORY_TEST_STA_END:
    
        break;
    case DOHOME_FACTORY_TEST_THIRD_PARTY:
        if(_third_party_enable){
            if(_third_party_scan_cb){
                DOHOME_LOG_I("start_third_party_test");
                _third_party_scan_cb(1);
            }     
        }
        _factory_test_sta = DOHOME_FACTORY_TEST_STA_IDEL;
        break;
#if (defined(FACTORY_TEST_CONTROL_ENABLE) && FACTORY_TEST_CONTROL_ENABLE == 1)
    case DOHOME_FACTORY_TEST_CONTROL:
        DOHOME_LOG_I("start_control_test");
        dt_test_control_start();
        _factory_test_sta = DOHOME_FACTORY_TEST_STA_IDEL;
        break;
#endif
    default:

        break;
    }

    loop_tick += DOHOME_FACTORY_TEST_LOOP_INTERVAL;
    loop_tick = (loop_tick)%(3600000);
}

#endif